package toy.keli.edic.util

import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSType
import com.google.devtools.ksp.symbol.KSTypeReference
import com.google.devtools.ksp.symbol.KSValueParameter
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import java.lang.reflect.Type
import kotlin.sequences.forEach

@Retention(AnnotationRetention.RUNTIME)  //表示这个注解在运行时可见，可以通过反射获取。
@Target(AnnotationTarget.FUNCTION)       //表示这个注解只能用于函数（方法）。
annotation class Permissions(vararg val values:String){
    companion object {
        fun <T> check(values:Array<String>,afterRun:()->T): T{
            PermissionUtil.getPermission(ActivityRun.context,values) {
                afterRun.invoke()
            }
            return afterRun.invoke()
        }
    }
}

open class ProcessorAspect(val codeGenerator: CodeGenerator,val logger: KSPLogger) : SymbolProcessor {
    override fun process(resolver: Resolver): List<KSAnnotated> {
        // 1. 获取所有被 @LogExecutionTime 注解的函数
        resolver.getSymbolsWithAnnotation("toy.keli.edic.."+Permissions::class).filterIsInstance<KSFunctionDeclaration>().forEach {func->
                // 获取注解参数
                val args = func.annotations.first {it.shortName.asString() == Permissions::class.simpleName}.let {
                     it.arguments.first().value as Array<String>
                }
                val writer = codeGenerator.createNewFile(
                        dependencies = Dependencies(false, func.containingFile ?: throw IllegalArgumentException("No containing file")),
                        packageName = func.packageName.toString(),
                        fileName = "${Permissions::class.simpleName}_aop",
                        extensionName = "kt"
                    ).bufferedWriter()
                //写入切片代码 添加文件
                FileSpec.builder(func.packageName.toString(), "${Permissions::class.simpleName}_aop").apply {
                    //添加方法
                    addFunction(FunSpec.builder("${func.simpleName}_aop").apply {
                        addModifiers(KModifier.INLINE)
                        // 添加原函数的参数
                        func.parameters.forEach { param ->
                            addParameter(name= param.name!!.asString(),type=param.type.resolve().toTypeName())
                        }
                        // 添加返回类型
                        func.returnType?.let {
                            returns(it.resolve().toTypeName())
                        }
                        val safeArgs = getSafeArgs(func.parameters)
                        val callOldCode = "return this.${func.simpleName}($safeArgs)"
                        addCode(proxyFunction(args,callOldCode), *func.parameters.map { it.name!!.asString() }.toTypedArray())
                    }.build())
                }.build().writeTo(writer)
        }
        return emptyList() // 返回未处理的符号，这里已全部处理
    }

    private fun getSafeArgs(params:List<KSValueParameter>): String {
        return params.map { param ->
            val type = param.type.resolve()
            "%L"
        }.joinToString()
    }

    private fun KSType.toTypeName() :Type{
        val qualifiedName = declaration.qualifiedName?.asString() ?: ""
        return   Class.forName(qualifiedName)
    }

    private fun FunSpec.Builder.proxyFunction(args: Array<String>, func: String) :String{
        val params = args.map{"'${it}'"}.joinToString(",")
        return  """
                    return Permissions.check($params){
                       $func
                    }
                """.trimIndent()
    }
}